Skin:
[NORMAL]
[BLUE] [DOS] [LIGHT]  / コピーするための表示 / 実行
このファイル: /home/web6047/www/cgi-bin/prj/20180707-SVC(Side View Character)/techtree/[E] batch/javascript - snap 20180715.html
1 <!DOCTYPE html>
2 <head>
3 <meta content="text/html; charset=UTF-8" http-equiv="content-type">
4 <title>batch</title>
5 <script>
6 /*
7 スクリプトを分析し、オブジェクト化する。
8 1行ずつステップ実行でき、
9 //anmのある行まで一気に実行することもできる。
10
11 アニメーションにおいて、1つのアニメが終わった後、別のアニメを実行したい。
12 1つのアニメを関数に定義して、次のアニメも関数に定義する。
13 それらの関数を呼び出す関数を定義し、実行する。
14
15 そのためには、まず1行についてアニメ処理となるようにする。
16
17
18 */
19
20 console.clear();
21 console.log( "=============== script ==============" );
22 function $( id ) { return document.getElementById( id ); }
23 var HereDocument = /\/\*\s*([^]*?)\s*\*\//;
24 // usage: var txt = ( function() { /*multiTXT*/ } ).toString().match( HereDocument )[ 1 ];
25
26 /*
27
28 サンプル:
29 onloadx() 関数からテキストを抽出し、instructionへ渡し、setInterval。
30 debugprint_recursive()
31
32 本体:
33 InstructionRE 実行環境
34 exec() instructionを実行
35 Instruction テキストを受け取り、プログラムとして解析。
36 analyze() テキストを解析し、階層構造を作成する。
37 escapeBrackets()
38 test()
39 test2();
40
41 */
42
43 //---以下 サンプル実行
44 function onloadx() {
45
46 var blocktext = test.toString().match( /\{([\s\S]*)\}/ )[ 1 ];
47 instruction1 = new Instruction( null, null, null, blocktext, null, 0, 0 );
48
49
50 var blocktext = test2.toString().match( /\{([\s\S]*)\}/ )[ 1 ];
51 instruction2 = new Instruction( null, null, null, blocktext, null, 0, 0 );
52
53 // debugprint_recursive( instruction1 );
54 console.log( "-------------------------" );
55
56 a = 1;
57 b = 5;
58
59 instruction1.exec();
60 instruction2.exec();
61 }
62 function debugprint_recursive( object, indent ) {
63 //check.
64 if( indent == null ) indent = "";
65
66 console.log( object.tp, "DEC[" + object.declaration + "]\tINST[" + object.instruction + "]\tARG[" + object.argtext + "]" );
67 for( var i = 0; i < object.children.length; i++ ) {
68 indent += "\t";
69 debugprint_recursive( object.children[ i ], indent );
70 indent = indent.substr( 0, indent.length - 1 );
71 }
72 }
73 //---以上 サンプル実行
74
75
76 //プログラムの命令クラス
77 function Instruction( declaration, instruction, argtext, blocktext, comment, level, tp ) {
78 /*
79 一般にプログラムの1命令は以下の4項目で成り立っているとここでは考える。
80
81 declaration instracion( argtext ) { blocktext }
82 宣言 命令 引数 ブロック
83
84 単語を以下のように略す。
85 decl inst( argt ) blkt
86
87 例:
88 a = b; //inst decl, argt, blktがない状態
89 if( a == b ) { .. } //inst( argt ) { blkt } declがない状態
90 else { .. } //inst { blkt } decl, argtがない状態
91 test(); //inst( argt ) decl, blktがない状態
92 function test() { .. } //decl inst( argt ) { blkt } すべてそろっている状態
93 var a; //decl inst argt, blktがない状態
94 var a = b; //decl inst argt, blktがない状態
95
96 引数の blocktext は analyze() にとおし、階層構造にして children へ収める。
97 */
98
99 this.level = level;
100 this.declaration = declaration;
101 this.instruction = instruction;
102 this.argtext = argtext;
103 this.blocktext = blocktext;
104 this.comment = comment;
105 this.children = new Array();
106
107 this.isAvailable = true;
108
109 //ブロック部分を解析
110 if( blocktext != null ) this.analyze( blocktext );
111
112 this.tp = tp;
113
114 this.childSeek = 0;
115 }
116 Instruction.prototype.exec = function() {
117 var envs = new Array(); //スタックとして使用
118 var env = {
119 object : this,
120 counter : 0,
121 next : null,
122 parentEnv : null,
123 intoBlk : true,
124 };
125
126 owner = this;
127
128 var func = function() {
129 //envs はこの中でいつまでも有効(クロージャ)
130 //env はこの中でいつまでも有効(クロージャ)
131 loop1: while( 1 ) {
132 //check. ループを抜ける
133 if( ! env.object.commentProcessed && env.object.comment && env.object.comment.match( /anm(\d+)/ ) ) {
134 env.object.commentProcessed = true;
135 var ms = Number( RegExp.$1 );
136 setTimeout( func, ms ); //ループへ戻る
137 break loop1;
138 }
139 env.object.commentProcessed = false;
140
141 //処理実行
142 switch( env.object.instruction ) {
143 //Y 制御 分岐
144 case "if":
145 env.intoBlk = eval( env.object.argtext );
146 //check. ifに対応するelseについて
147 if( env.next && env.next.instruction == "else" ) {
148 env.next.elseCancel = env.intoBlk;
149 }
150 break;
151 case "else":
152 break;
153 //O 制御 繰り返し
154 case "for":
155 if( typeof env.forInit === "undefined" ) {
156 if( env.object.argtext.match( /(.*);(.*);(.*)/ ) ) {
157 env.forInit = RegExp.$1;
158 env.forCond = RegExp.$2;
159 env.forAdd = RegExp.$3;
160 } else {
161 console.log( "syntax erro on for: " + env.object.argtext );
162 }
163 env.forInit = env.forInit.replace( /var\s+/, "env." );
164 eval( env.forInit );
165 } else {
166 with( env ) eval( env.forAdd );
167 }
168 with( env ) env.intoBlk = eval( env.forCond );
169 break;
170 //I 制御 順次
171 default:
172 var script = "";
173 if( env.object.declaration == "function" ) {
174 script += "env.parentEnv.";
175 script += env.object.instruction + " = function( ";
176 script += env.object.argtext + " ) { ";
177 script += env.object.blocktext + " }";
178 env.intoBlk = false;
179 } else if( env.object.declaration == "var" ) {
180 script += "env.";
181 script += env.object.instruction;
182 env.intoBlk = false;
183 } else if( env.object.instruction != null ) {
184 script += env.object.instruction;
185 if( env.object.argtext != null ) script += "(" + env.object.argtext + ")";
186 if( env.object.blocktext != null ) script += "{" + env.object.blocktext + "}";
187 } else {
188 //コメント行などの場合はここに来る。
189 break;
190 }
191
192 //宣言や命令文の実行
193 var allWith = "";
194 for( var j = 1; j < envs.length - 1; j++ ) {
195 allWith += "with( envs[ " + j + " ] ) ";
196 }
197 if( env.parentEnv ) allWith += "with( env.parentEnv ) ";
198
199 eval( allWith + script );
200 }
201
202 //check. 子の走査が終了した?
203 while( env.object.elseCancel || ! env.intoBlk || env.counter == env.object.children.length ) {
204 //check. 最上位である?
205 if( envs.length == 0 ) break loop1;
206 //check. forである
207 if( env.object.instruction == "for" && env.intoBlk ) {
208 env.counter = 0;
209 continue loop1;
210 }
211 //親へ戻る
212 env = envs.pop();
213 }
214
215 //次の子へ移る
216 envs.push( env );
217 env = {
218 object : env.object.children[ env.counter++ ],
219 next : env.object.children[ env.counter ],
220 counter : 0,
221 intoBlk : true,
222 parentEnv : env,
223 }
224
225 }//loop1:while
226
227 };//func()
228
229
230 func();
231
232 };
233 Instruction.prototype.analyze = function( text ) {
234 /*
235 text を受け取り、内容を解析して階層構造を見い出し、childrenへ収める。
236 返り値はなし。
237
238 流れ:
239 //1. 不要なタブと改行を削除する。
240 //2. 括弧で囲まれた部分を退避する。(すると入れ子構造がなくなり4項目の取得が行いやすくなる)
241 //3. そのテキストを解析。各行の形状別に4項目を取得
242 //4. 4項目のうち argtext と blocktext について、退避した括弧部分を展開
243 //5. 4項目から新しいinstructionを生成する(階層構造となる)
244 */
245
246
247 //1. 不要なタブと改行を削除する。
248
249 text = text.replace( /^\t+/mg, " " ); //行頭のタブを半角スペース1個にする
250 text = text.replace( /\n/g, ";" ); //改行を半角スペース1個にする
251
252 //2. 括弧で囲まれた部分を退避する。
253 //(すると入れ子構造がなくなり1行1行の4項目の取得が行いやすくなる)
254
255 var res = escapeBrackets( text, "{", "}", "_block_#_;", true );
256 var blocks = res.contents;
257
258 var res = escapeBrackets( res.text, "(", ")", "_kakko_#_" );
259 var kakkos = res.contents;
260
261 var text2 = res.text;
262 text2 = text2.replace( /;\s+/mg, ";" );
263 text2 = text2.replace( /^\s+/gm, "" );
264
265 //3. そのテキストを解析。
266
267 var lines = text2.split( /;/ );
268 for( var i = 0; i < lines.length; i++ ) {
269 var line = lines[ i ];
270 //check. 空行はスキップ
271 if( line.match( /^\s*$/ ) ) continue;
272
273 //1命令を構成する4項目
274 var declaration = null;
275 var instruction = null;
276 var argtext = null;
277 var blocktext = null;
278 var comment = null;
279
280 var tp;
281
282 //コメントを処理
283 if( line.match( /\/\// ) ) {
284 line = RegExp.leftContext;
285 comment = RegExp.rightContext;
286 comment = comment.replace( /^\s+|\s+$/g, "" );
287 }
288
289 //各行の形状別に4項目を取得
290 if( line.match( /(var\s+|)(.+=.+)/ ) ) { //var a=b または a=b
291
292 tp = 4;
293 declaration = RegExp.$1;
294 instruction = RegExp.$2;
295
296 } else if( line.match( /(var\s+)(.+)/ ) ) { //var a
297
298 tp = 1;
299 declaration = RegExp.$1;
300 instruction = RegExp.$2;
301
302 } else if( line.match( /(function\s+|)(.+)\((.*)\)(.+)/ ) ) { //function f() .. または if(true) ..など
303
304 tp = 2;
305 declaration = RegExp.$1;
306 instruction = RegExp.$2;
307 argtext = RegExp.$3;
308 blocktext = RegExp.$4;
309
310 } else if( line.match( /(.+)\((.*)\)/ ) ) { //func();
311
312 tp = 2;
313 instruction = RegExp.$1;
314 argtext = RegExp.$2;
315
316 } else if( line.match( /(.*)\s(.*)/ ) ) { //else ..
317
318 tp = 3;
319 instruction = RegExp.$1;
320 blocktext = RegExp.$2;
321 } else if( comment != null ) { //コメント行
322
323 tp = 5;
324
325 } else {
326
327 console.log( "syntax error: " + ": [" + line + "]" );
328 continue;
329
330 }
331
332 //4. 4項目のうち argtext と blocktext について、退避した括弧部分を展開
333
334 if( argtext != null && argtext.match( /_kakko_(\d+)_/ ) ) {
335 argtext = kakkos[ RegExp.$1 ];
336 }
337
338 if( blocktext != null ) {
339
340 //if() {..}ではなく、if() .. の形で .. の部分で退避された括弧を展開
341 while( blocktext.match( /_kakko_(\d+)_/ ) ) {
342 blocktext = RegExp.leftContext + kakkos[ RegExp.$1 ] + RegExp.rightContext;
343 }
344
345 if( blocktext.match( /_block_(\d+)_/ ) ) {
346 blocktext = blocks[ RegExp.$1 ];
347 }
348 }
349
350 //先頭または末尾のスペースを除去
351 if( declaration != null ) declaration = declaration.replace( /^\s+|\s+$/, "" );
352
353 //5. 4項目から新しい instruction を生成する(階層構造となる)
354 this.children.push( new Instruction( declaration, instruction, argtext, blocktext, comment, this.level + 1, tp ) );
355
356 }//for i
357 }
358 function escapeBrackets( text, startBracket, endBracket, identifier, swDelBracket ) {
359 /*
360 テキスト中の括弧を配列へ退避する。
361 処理結果は複数あるので、オブジェクトを返り値として返している。
362
363 usage: var res = escapeBrackets( text, "(", ")", "_kakko_#_" );
364 usage: var res = escapeBrackets( text, "{", "}", "_block_#_", true );
365
366 引数:
367 text 処理したいテキスト
368 startBracket 開始括弧文字指定
369 endBracket 終了括弧文字指定
370 identifier テキスト中の括弧でくくられた部分をこの識別子に置き換える。
371 識別子文字列内の#は通し番号に置き換わる。
372 swDelBracket 括弧でくくられた部分を識別子に置き換えた際、括弧を削除するか。
373 たとえば、
374 if( true ) { .. }
375 のとき、()と{}を処理するとして、
376 {}についてはswDelBracketをtrueにして処理すると、
377 if( _kakko_0 ) {_block_0_}
378 にはならず、
379 if( _kakko_0 ) _block_0_
380 のようになる。
381 つまり、ifの条件部分の括弧()は消したくないが、{}は消したいときに利用する。
382 返り値:
383 res.text
384 引数のtextを処理した結果。
385 text中の括弧でくくられた部分は identifier に置き換わっている。
386 res.contents
387 text中の括弧でくくられた部分を収めた配列。
388 結果のテキスト内の identifier 部分にあたるテキストを収めている。
389 たとえば、
390 res.contents[ 0 ] はテキスト中の1個目の括弧内、
391 res.contents[ 1 ] はテキスト中の2個目の括弧内となる。
392 */
393 var res = {
394 text : "",
395 contents : new Array()
396 };
397
398 var level = 0;
399 var buffer = "";
400 var tail = text;
401 var bracketSearchKey = "[" + startBracket + endBracket + "]";
402
403 while( tail.match( bracketSearchKey ) ) {
404 var bracket = RegExp.lastMatch;
405 var left = RegExp.leftContext;
406 tail = RegExp.rightContext;
407
408 //括弧内の場合は取得し、括弧外(level==0)のときは結果のテキストへ
409 if( level > 0 )
410 buffer += left;
411 else
412 res.text += left;
413
414 //括弧閉じである
415 if( bracket == endBracket ) {
416 level --;
417 //check. 対応する括弧であるとき
418 if( level == 0 ) {
419 var id = identifier.replace( "#", res.contents.length );
420 res.text += id;
421 res.contents.push( buffer );
422 buffer = "";
423 }
424 }
425
426 //括弧そのものは、外側の他の括弧内の場合は取得し、
427 //括弧外(level==0)のときは削除指定でなければ結果のテキストへ
428 if( level > 0 )
429 buffer += bracket;
430 else if( ! swDelBracket )
431 res.text += bracket;
432
433 //括弧開始である
434 if( bracket == startBracket ) {
435 level ++;
436 }
437 }
438 res.text += tail;
439
440 return res;
441 }
442
443 //サンプル
444 function test() {
445 var b;
446 var c=b;
447 console.log( 1 );
448 if( a == (1+1)*2 || true ) {
449 b = 3;
450 if( false ) {}
451 } else {
452 b = 10;
453 }
454 mes = "スライムがあられた!";
455 for( var i = 0; i < mes.length; i++ ) {
456 console.log( mes.substr( i, 1 ) ); //anm100
457 }
458 if( true ) console.log(3);
459 function abc( x, y ) {
460 console.log(4);
461 }
462 abc( 1, 2 );
463 }
464 function test2() {
465 console.log( 123 ); //anm500
466 console.log( 1234 ); //anm500
467 console.log(1);
468 }
469
470 </script>
471 <style>
472 </style>
473 </head>
474 <body onload="onloadx();" style="">
475 <pre>
476 下記の方法で JavaScript コンソールを開いてページ更新してください。
477
478 JavaScript コンソールを開くには:
479 たいていのブラウザは … CTRL+SHIFT+J を押す。
480 InternetExplorer の場合は … F12 を押してから CTRL+2 を押す。
481
482 <a href="javascript:location.reload();">ページ更新</a>
483 </pre>
484 </body>
485 </html>